package com.datagateway.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 数据传输加密管理器
 * 负责数据传输过程中的加密和SSL/TLS配置
 * 
 * @author Data Gateway Team
 * @version 1.0.0
 */
@Component
public class DataTransmissionEncryptionManager {

    private static final Logger logger = LoggerFactory.getLogger(DataTransmissionEncryptionManager.class);

    @Autowired
    private DataEncryptionManager dataEncryptionManager;

    @Autowired
    private AlertManager alertManager;

    @Autowired
    private SystemMonitor systemMonitor;

    /**
     * 传输加密统计信息
     */
    private final AtomicLong totalTransmissions = new AtomicLong(0);
    private final AtomicLong totalTransmissionTime = new AtomicLong(0);
    private final AtomicLong totalTransmissionSize = new AtomicLong(0);
    private final AtomicLong totalTransmissionErrors = new AtomicLong(0);

    /**
     * 传输加密配置
     */
    private boolean transmissionEncryptionEnabled = true;
    private String sslProtocol = "TLSv1.3";
    private String cipherSuite = "TLS_AES_256_GCM_SHA384";
    private boolean sslVerificationEnabled = true;
    private int connectionTimeout = 30000;
    private int readTimeout = 60000;

    /**
     * 会话密钥管理
     */
    private final Map<String, SessionKey> sessionKeys = new ConcurrentHashMap<>();
    private final Map<String, TransmissionChannel> transmissionChannels = new ConcurrentHashMap<>();
    private int sessionKeyExpirationMinutes = 60;
    private int maxSessionKeys = 1000;

    /**
     * 传输通道配置
     */
    private final Map<String, ChannelEncryptionConfig> channelConfigs = new ConcurrentHashMap<>();

    /**
     * 初始化传输加密管理器
     */
    public void initialize() {
        try {
            // 初始化SSL上下文
            initializeSSLContext();
            
            // 初始化默认传输通道
            initializeDefaultChannels();
            
            // 启动会话密钥清理任务
            startSessionKeyCleanupTask();
            
            logger.info("数据传输加密管理器初始化成功");
            
        } catch (Exception e) {
            logger.error("数据传输加密管理器初始化失败", e);
            alertManager.sendSystemErrorAlert("数据传输加密管理器初始化失败", e.getMessage());
        }
    }

    /**
     * 加密传输数据
     * 
     * @param data 要传输的数据
     * @param channelId 传输通道ID
     * @return 加密后的传输数据
     */
    public EncryptedTransmissionData encryptTransmissionData(String data, String channelId) {
        if (!transmissionEncryptionEnabled || data == null || data.isEmpty()) {
            return new EncryptedTransmissionData(data, null, null, null, false);
        }

        long startTime = System.currentTimeMillis();
        
        try {
            // 获取或创建会话密钥
            SessionKey sessionKey = getOrCreateSessionKey(channelId);
            if (sessionKey == null) {
                logger.warn("无法获取会话密钥: {}", channelId);
                return new EncryptedTransmissionData(data, null, null, null, false);
            }

            // 使用会话密钥加密数据
            EncryptedData encryptedData = dataEncryptionManager.encryptData(data, sessionKey.getKeyAlias());
            
            if (encryptedData.isEncrypted()) {
                // 更新统计信息
                totalTransmissions.incrementAndGet();
                totalTransmissionTime.addAndGet(System.currentTimeMillis() - startTime);
                totalTransmissionSize.addAndGet(data.length());
                
                logger.debug("传输数据加密成功: {} -> {} 字节", data.length(), encryptedData.getData().length());
                
                return new EncryptedTransmissionData(
                    encryptedData.getData(),
                    encryptedData.getIv(),
                    sessionKey.getKeyId(),
                    channelId,
                    true
                );
            } else {
                return new EncryptedTransmissionData(data, null, null, null, false);
            }
            
        } catch (Exception e) {
            totalTransmissionErrors.incrementAndGet();
            logger.error("传输数据加密失败", e);
            alertManager.sendSystemErrorAlert("传输数据加密失败", e.getMessage());
            return new EncryptedTransmissionData(data, null, null, null, false);
        }
    }

    /**
     * 解密传输数据
     * 
     * @param encryptedData 加密的传输数据
     * @return 解密后的数据
     */
    public String decryptTransmissionData(EncryptedTransmissionData encryptedData) {
        if (!transmissionEncryptionEnabled || encryptedData == null || !encryptedData.isEncrypted()) {
            return encryptedData != null ? encryptedData.getData() : null;
        }

        long startTime = System.currentTimeMillis();
        
        try {
            // 获取会话密钥
            SessionKey sessionKey = getSessionKey(encryptedData.getKeyId());
            if (sessionKey == null) {
                logger.warn("未找到会话密钥: {}", encryptedData.getKeyId());
                return encryptedData.getData();
            }

            // 创建EncryptedData对象进行解密
            DataEncryptionManager.EncryptedData encrypted = new DataEncryptionManager.EncryptedData(
                encryptedData.getData(),
                encryptedData.getIv(),
                sessionKey.getKeyAlias(),
                dataEncryptionManager.getStatistics().getDefaultAlgorithm(),
                true
            );
            
            String decryptedData = dataEncryptionManager.decryptData(encrypted);
            
            // 更新统计信息
            totalTransmissionTime.addAndGet(System.currentTimeMillis() - startTime);
            
            logger.debug("传输数据解密成功: {} 字节", decryptedData.length());
            
            return decryptedData;
            
        } catch (Exception e) {
            totalTransmissionErrors.incrementAndGet();
            logger.error("传输数据解密失败", e);
            alertManager.sendSystemErrorAlert("传输数据解密失败", e.getMessage());
            return encryptedData.getData();
        }
    }

    /**
     * 建立安全传输通道
     * 
     * @param channelId 通道ID
     * @param config 通道配置
     * @return 是否建立成功
     */
    public boolean establishSecureChannel(String channelId, ChannelEncryptionConfig config) {
        try {
            // 生成会话密钥
            SessionKey sessionKey = generateSessionKey(channelId);
            if (sessionKey == null) {
                return false;
            }
            
            // 创建传输通道
            TransmissionChannel channel = new TransmissionChannel(
                channelId,
                config,
                sessionKey,
                System.currentTimeMillis()
            );
            
            transmissionChannels.put(channelId, channel);
            channelConfigs.put(channelId, config);
            
            logger.info("安全传输通道已建立: {}", channelId);
            
            return true;
            
        } catch (Exception e) {
            logger.error("建立安全传输通道失败: {}", channelId, e);
            alertManager.sendSystemErrorAlert("建立安全传输通道失败", e.getMessage());
            return false;
        }
    }

    /**
     * 关闭安全传输通道
     * 
     * @param channelId 通道ID
     * @return 是否关闭成功
     */
    public boolean closeSecureChannel(String channelId) {
        try {
            TransmissionChannel channel = transmissionChannels.remove(channelId);
            if (channel != null) {
                // 清理会话密钥
                sessionKeys.remove(channel.getSessionKey().getKeyId());
                channelConfigs.remove(channelId);
                
                logger.info("安全传输通道已关闭: {}", channelId);
                return true;
            }
            
            return false;
            
        } catch (Exception e) {
            logger.error("关闭安全传输通道失败: {}", channelId, e);
            return false;
        }
    }

    /**
     * 获取传输通道状态
     * 
     * @param channelId 通道ID
     * @return 通道状态
     */
    public TransmissionChannel getChannelStatus(String channelId) {
        return transmissionChannels.get(channelId);
    }

    /**
     * 获取所有传输通道状态
     * 
     * @return 通道状态列表
     */
    public List<TransmissionChannel> getAllChannelStatus() {
        return new ArrayList<>(transmissionChannels.values());
    }

    /**
     * 验证传输数据完整性
     * 
     * @param data 传输数据
     * @param checksum 校验和
     * @return 验证结果
     */
    public boolean verifyTransmissionIntegrity(String data, String checksum) {
        try {
            String calculatedChecksum = calculateChecksum(data);
            boolean isValid = calculatedChecksum.equals(checksum);
            
            if (!isValid) {
                logger.warn("传输数据完整性验证失败");
                alertManager.sendSystemErrorAlert("传输数据完整性验证失败", "数据可能被篡改");
            }
            
            return isValid;
            
        } catch (Exception e) {
            logger.error("传输数据完整性验证异常", e);
            return false;
        }
    }

    /**
     * 获取传输加密统计信息
     * 
     * @return 传输加密统计信息
     */
    public TransmissionEncryptionStatistics getStatistics() {
        return new TransmissionEncryptionStatistics(
            totalTransmissions.get(),
            totalTransmissionTime.get(),
            totalTransmissionSize.get(),
            totalTransmissionErrors.get(),
            sessionKeys.size(),
            transmissionChannels.size(),
            transmissionEncryptionEnabled,
            sslProtocol,
            cipherSuite,
            sslVerificationEnabled,
            System.currentTimeMillis()
        );
    }

    /**
     * 设置传输加密配置
     * 
     * @param enabled 是否启用传输加密
     * @param sslProtocol SSL协议版本
     * @param cipherSuite 密码套件
     * @param verificationEnabled 是否启用SSL验证
     * @param connectionTimeout 连接超时时间
     * @param readTimeout 读取超时时间
     */
    public void setTransmissionConfig(boolean enabled, String sslProtocol, String cipherSuite,
                                    boolean verificationEnabled, int connectionTimeout, int readTimeout) {
        this.transmissionEncryptionEnabled = enabled;
        this.sslProtocol = sslProtocol;
        this.cipherSuite = cipherSuite;
        this.sslVerificationEnabled = verificationEnabled;
        this.connectionTimeout = connectionTimeout;
        this.readTimeout = readTimeout;
        
        logger.info("传输加密配置已更新: 启用={}, SSL协议={}, 密码套件={}, 验证={}, 连接超时={}, 读取超时={}", 
                   enabled, sslProtocol, cipherSuite, verificationEnabled, connectionTimeout, readTimeout);
    }

    /**
     * 初始化SSL上下文
     */
    private void initializeSSLContext() throws Exception {
        if (!sslVerificationEnabled) {
            // 创建信任所有证书的TrustManager（仅用于测试环境）
            TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() { return null; }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) { }
                    public void checkServerTrusted(X509Certificate[] certs, String authType) { }
                }
            };
            
            SSLContext sslContext = SSLContext.getInstance(sslProtocol);
            sslContext.init(null, trustAllCerts, new SecureRandom());
            
            logger.warn("SSL验证已禁用，仅用于测试环境");
        }
        
        logger.info("SSL上下文初始化完成: {}", sslProtocol);
    }

    /**
     * 初始化默认传输通道
     */
    private void initializeDefaultChannels() {
        // 创建默认的Kafka传输通道
        ChannelEncryptionConfig kafkaConfig = new ChannelEncryptionConfig(
            "kafka",
            true,
            sslProtocol,
            cipherSuite,
            connectionTimeout,
            readTimeout
        );
        
        establishSecureChannel("kafka-default", kafkaConfig);
        
        // 创建默认的Hive传输通道
        ChannelEncryptionConfig hiveConfig = new ChannelEncryptionConfig(
            "hive",
            true,
            sslProtocol,
            cipherSuite,
            connectionTimeout,
            readTimeout
        );
        
        establishSecureChannel("hive-default", hiveConfig);
        
        logger.info("默认传输通道初始化完成");
    }

    /**
     * 启动会话密钥清理任务
     */
    private void startSessionKeyCleanupTask() {
        Timer timer = new Timer("session-key-cleanup", true);
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                cleanupExpiredSessionKeys();
            }
        }, 60000, 300000); // 每5分钟清理一次
    }

    /**
     * 清理过期的会话密钥
     */
    private void cleanupExpiredSessionKeys() {
        try {
            long currentTime = System.currentTimeMillis();
            long expirationTime = sessionKeyExpirationMinutes * 60 * 1000;
            
            int cleanedCount = 0;
            Iterator<Map.Entry<String, SessionKey>> iterator = sessionKeys.entrySet().iterator();
            
            while (iterator.hasNext()) {
                Map.Entry<String, SessionKey> entry = iterator.next();
                SessionKey sessionKey = entry.getValue();
                
                if (currentTime - sessionKey.getCreateTime() > expirationTime) {
                    iterator.remove();
                    cleanedCount++;
                }
            }
            
            if (cleanedCount > 0) {
                logger.info("清理过期会话密钥: {} 个", cleanedCount);
            }
            
        } catch (Exception e) {
            logger.error("清理过期会话密钥失败", e);
        }
    }

    /**
     * 获取或创建会话密钥
     * 
     * @param channelId 通道ID
     * @return 会话密钥
     */
    private SessionKey getOrCreateSessionKey(String channelId) {
        TransmissionChannel channel = transmissionChannels.get(channelId);
        if (channel != null) {
            return channel.getSessionKey();
        }
        
        // 创建新的会话密钥
        return generateSessionKey(channelId);
    }

    /**
     * 获取会话密钥
     * 
     * @param keyId 密钥ID
     * @return 会话密钥
     */
    private SessionKey getSessionKey(String keyId) {
        return sessionKeys.get(keyId);
    }

    /**
     * 生成会话密钥
     * 
     * @param channelId 通道ID
     * @return 会话密钥
     */
    private SessionKey generateSessionKey(String channelId) {
        try {
            String keyId = "session_" + channelId + "_" + System.currentTimeMillis();
            String keyAlias = "session_" + UUID.randomUUID().toString().substring(0, 8);
            
            // 生成新的加密密钥
            dataEncryptionManager.generateNewKey(keyAlias);
            
            SessionKey sessionKey = new SessionKey(
                keyId,
                keyAlias,
                channelId,
                System.currentTimeMillis()
            );
            
            sessionKeys.put(keyId, sessionKey);
            
            logger.debug("会话密钥已生成: {} -> {}", channelId, keyId);
            
            return sessionKey;
            
        } catch (Exception e) {
            logger.error("生成会话密钥失败: {}", channelId, e);
            return null;
        }
    }

    /**
     * 计算数据校验和
     * 
     * @param data 数据
     * @return 校验和
     */
    private String calculateChecksum(String data) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            logger.error("计算校验和失败", e);
            return "";
        }
    }

    /**
     * 加密传输数据类
     */
    public static class EncryptedTransmissionData {
        private final String data;
        private final String iv;
        private final String keyId;
        private final String channelId;
        private final boolean encrypted;

        public EncryptedTransmissionData(String data, String iv, String keyId, String channelId, boolean encrypted) {
            this.data = data;
            this.iv = iv;
            this.keyId = keyId;
            this.channelId = channelId;
            this.encrypted = encrypted;
        }

        // Getter方法
        public String getData() { return data; }
        public String getIv() { return iv; }
        public String getKeyId() { return keyId; }
        public String getChannelId() { return channelId; }
        public boolean isEncrypted() { return encrypted; }
    }

    /**
     * 会话密钥类
     */
    public static class SessionKey {
        private final String keyId;
        private final String keyAlias;
        private final String channelId;
        private final long createTime;

        public SessionKey(String keyId, String keyAlias, String channelId, long createTime) {
            this.keyId = keyId;
            this.keyAlias = keyAlias;
            this.channelId = channelId;
            this.createTime = createTime;
        }

        // Getter方法
        public String getKeyId() { return keyId; }
        public String getKeyAlias() { return keyAlias; }
        public String getChannelId() { return channelId; }
        public long getCreateTime() { return createTime; }
    }

    /**
     * 传输通道类
     */
    public static class TransmissionChannel {
        private final String channelId;
        private final ChannelEncryptionConfig config;
        private final SessionKey sessionKey;
        private final long createTime;

        public TransmissionChannel(String channelId, ChannelEncryptionConfig config, SessionKey sessionKey, long createTime) {
            this.channelId = channelId;
            this.config = config;
            this.sessionKey = sessionKey;
            this.createTime = createTime;
        }

        // Getter方法
        public String getChannelId() { return channelId; }
        public ChannelEncryptionConfig getConfig() { return config; }
        public SessionKey getSessionKey() { return sessionKey; }
        public long getCreateTime() { return createTime; }
    }

    /**
     * 通道加密配置类
     */
    public static class ChannelEncryptionConfig {
        private final String channelType;
        private final boolean encryptionEnabled;
        private final String sslProtocol;
        private final String cipherSuite;
        private final int connectionTimeout;
        private final int readTimeout;

        public ChannelEncryptionConfig(String channelType, boolean encryptionEnabled, String sslProtocol,
                                     String cipherSuite, int connectionTimeout, int readTimeout) {
            this.channelType = channelType;
            this.encryptionEnabled = encryptionEnabled;
            this.sslProtocol = sslProtocol;
            this.cipherSuite = cipherSuite;
            this.connectionTimeout = connectionTimeout;
            this.readTimeout = readTimeout;
        }

        // Getter方法
        public String getChannelType() { return channelType; }
        public boolean isEncryptionEnabled() { return encryptionEnabled; }
        public String getSslProtocol() { return sslProtocol; }
        public String getCipherSuite() { return cipherSuite; }
        public int getConnectionTimeout() { return connectionTimeout; }
        public int getReadTimeout() { return readTimeout; }
    }

    /**
     * 传输加密统计信息类
     */
    public static class TransmissionEncryptionStatistics {
        private final long totalTransmissions;
        private final long totalTransmissionTime;
        private final long totalTransmissionSize;
        private final long totalTransmissionErrors;
        private final int sessionKeyCount;
        private final int channelCount;
        private final boolean transmissionEncryptionEnabled;
        private final String sslProtocol;
        private final String cipherSuite;
        private final boolean sslVerificationEnabled;
        private final long timestamp;

        public TransmissionEncryptionStatistics(long totalTransmissions, long totalTransmissionTime,
                                              long totalTransmissionSize, long totalTransmissionErrors,
                                              int sessionKeyCount, int channelCount, boolean transmissionEncryptionEnabled,
                                              String sslProtocol, String cipherSuite, boolean sslVerificationEnabled,
                                              long timestamp) {
            this.totalTransmissions = totalTransmissions;
            this.totalTransmissionTime = totalTransmissionTime;
            this.totalTransmissionSize = totalTransmissionSize;
            this.totalTransmissionErrors = totalTransmissionErrors;
            this.sessionKeyCount = sessionKeyCount;
            this.channelCount = channelCount;
            this.transmissionEncryptionEnabled = transmissionEncryptionEnabled;
            this.sslProtocol = sslProtocol;
            this.cipherSuite = cipherSuite;
            this.sslVerificationEnabled = sslVerificationEnabled;
            this.timestamp = timestamp;
        }

        // Getter方法
        public long getTotalTransmissions() { return totalTransmissions; }
        public long getTotalTransmissionTime() { return totalTransmissionTime; }
        public long getTotalTransmissionSize() { return totalTransmissionSize; }
        public long getTotalTransmissionErrors() { return totalTransmissionErrors; }
        public int getSessionKeyCount() { return sessionKeyCount; }
        public int getChannelCount() { return channelCount; }
        public boolean isTransmissionEncryptionEnabled() { return transmissionEncryptionEnabled; }
        public String getSslProtocol() { return sslProtocol; }
        public String getCipherSuite() { return cipherSuite; }
        public boolean isSslVerificationEnabled() { return sslVerificationEnabled; }
        public long getTimestamp() { return timestamp; }
    }
}
